package com.modular.extra.fm.data;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.ToolOpt;
import com.c.opt.ComOpt;
import com.modular.extra.fm.FactoryFmOpt;
import com.modular.extra.fm.device.opt.OptFmDevice;
import com.modular.iot.bean.ThingsProductDo;
import com.modular.iot.bo.IotData;
import com.modular.iot.bo.IotDataItem;
import com.modular.iot.bo.IotDataQueryInBo;
import ntd.util.ToolLock;
import ntd.util.UtilRun;
import ntd.util.frame.task.handle.fm.bo.FmDataRecordBo;
import ntd.util.frame.task.handle.fm.bo.FmDataRecordItemBo;
import ntd.util.frame.task.handle.fm.bo.FmDataRecordRule;
import ntd.util.frame.task.handle.fm.enums.EnumDataAnomaly;
import ntd.util.frame.task.handle.fm.util.ToolFmData;
import ntd.util.frame.task.handle.fm.util.UtilFmMsg;
import ntd.util.modular.data.util.handle.constant.Constant212;
import ntd.util.modular.data.util.handle.tool.Tool212;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

import static ntd.util.frame.task.handle.fm.util.ToolFmData.OPT_FM_DATA_PUSH;

public class OptFmData {

    private OptFmDevice optFmDevice = FactoryFmOpt.OPT_FM_DEVICE;

    // 基站设备操作
    public ComOpt<FmDataRecordBo> dataRecordOpt = ToolOpt.get("data_record", FactoryFmOpt.DS_ID, FmDataRecordBo.class);

    private static Map<String, String> map = new HashMap<>();

    static {
        // 广茂大街9号-供水井1
        map.put("861878048776774", "mn110115030001");
        // 金苑路-雨水井2
        map.put("220228002", "mn110115020002");
        // 金苑路-雨水井1
        map.put("0861428040522188", "mn110115020001");
        map.put("220228001", "mn110115020001");
        // 金苑路-热力井2
        map.put("869976032648314", "mn110115010002");
        // 金苑路-热力井1
        map.put("869976032709801", "mn110115010001");
        // 金苑路-污水井1
        map.put("AMT22030911130007", "mn110115040001");
        map.put("0861428041703415", "mn110115040001");
    }

    
    public FmDataRecordBo getDataRecord(String mn, String cn, String currentTimeStr) {
        return dataRecordOpt.query().eq("mn", mn).eq("cn", cn).eq("create_time", currentTimeStr).getBean();
    }

    /**
     * 初始化 基站数据信息
     *
     * @param mn
     * @param cn
     * @param ruleId
     * @param currentTimeStr
     * @param exceptionLevel 异常级别 {@link EnumDataAnomaly - exceptionLevel}
     * @return
     */
    public FmDataRecordBo initDataRecord(String mn, String cn, String ruleId, String currentTimeStr, int exceptionLevel) {
        String fmCn = StrUtil.subSuf(cn, -2);
        AtomicReference<FmDataRecordBo> fmDataRecordBo = new AtomicReference<>();
        ToolLock.lockRun("initDataRecord" + mn + cn + currentTimeStr, () -> {
            FmDataRecordBo dataRecord = getDataRecord(mn, fmCn, currentTimeStr);
            if (ObjectUtil.isNull(dataRecord)) {
                StaticLog.info("开始同步数据[{}][{}][{}]到开放平台", mn, fmCn, currentTimeStr);
                dataRecord = FmDataRecordBo.init(mn, fmCn, ruleId, currentTimeStr);
                // 异常级别封装
                switch (exceptionLevel) {
                    case 1: dataRecord.setHasA(1); break;
                    case 2: dataRecord.setHasO(1); break;
                    case 3: dataRecord.setHasE(1); break;
                }
                dataRecord.setId(dataRecordOpt.syncBean(dataRecord));
            }
            fmDataRecordBo.set(dataRecord);
        });
        return fmDataRecordBo.get();
    }

    /**
     * 实时数据查询
     * @param mn
     * @return
     */
    public FmDataRecordBo newData(String mn) {
        IotDataQueryInBo iotDataQueryInBo = new IotDataQueryInBo();
        iotDataQueryInBo.setDeviceCode(mn);
        iotDataQueryInBo.setCn("2011");
        iotDataQueryInBo.setSize(1);
        List<IotData> iotDatas = ToolOpt.OPT_T_DATA.queryIotData(iotDataQueryInBo).getRecords();
        if (CollUtil.isEmpty(iotDatas)) {
            return null;
        }
        IotData iotData = iotDatas.get(0);
        // 查询基站因子标准信息
        List<FmDataRecordRule> fmDataRules = FactoryFmOpt.OPT_FM_FACTOR_RULE.listDataRuleBo(ListUtil.of(iotData.getMn()));
        // 数据标准分组
        Map<String, FmDataRecordRule> fmDataRecordRuleMap = CollStreamUtil.toIdentityMap(fmDataRules, FmDataRecordRule::getFactorCode);
        List<FmDataRecordItemBo> fmDataRecordItemBos = new ArrayList<>();
        for (IotDataItem iotDataItem : iotData.getIotDataItems()) {
            // 对象转换
            FmDataRecordItemBo fmDataRecordItemBo = FmDataRecordItemBo.transform(iotDataItem);
            // 计算超标情况
            handleDataStand(fmDataRecordRuleMap.get(fmDataRecordItemBo.getFactorCode()), fmDataRecordItemBo);
            // 保存超标情况信息
            fmDataRecordItemBos.add(fmDataRecordItemBo);
        }
        FmDataRecordBo transform = FmDataRecordBo.transform(iotDatas.get(0));
        transform.setDataRecordItemList(fmDataRecordItemBos);
        return transform;
    }

    public boolean pushData(IotData iotData) {
        // 查询基站因子标准信息
        List<FmDataRecordRule> fmDataRules = FactoryFmOpt.OPT_FM_FACTOR_RULE.listDataRuleBo(ListUtil.of(iotData.getMn()));
        // 开始同步数据
        // 1. 数据标准规则id
        AtomicReference<String> ruleId = new AtomicReference<>();
        Opt.ofEmptyAble(fmDataRules).ifPresent(fmDataRecordRules -> ruleId.set(fmDataRecordRules.get(0).getRuleId()));
        // 数据标准分组
        Map<String, FmDataRecordRule> fmDataRecordRuleMap = CollStreamUtil.toIdentityMap(fmDataRules, FmDataRecordRule::getFactorCode);
        // 各因子超标
        boolean isException = false;
        Map<String, EnumDataAnomaly> enumDataAnomalyMap = new HashMap<>();
        // 计算后对象
        List<FmDataRecordItemBo> fmDataRecordItemBos = new ArrayList<>();
        // 默认异常级别为正常
        int exceptionLevel = 0;
        // 遍历子数据列表
        for (IotDataItem iotDataItem : iotData.getIotDataItems()) {
            // 对象转换
            FmDataRecordItemBo fmDataRecordItemBo = FmDataRecordItemBo.transform(iotDataItem);
            // 计算超标情况
            EnumDataAnomaly enumDataAnomaly = handleDataStand(fmDataRecordRuleMap.get(fmDataRecordItemBo.getFactorCode()), fmDataRecordItemBo);
            // 保存超标情况信息
            isException = enumDataAnomaly.isException() || isException;
            // 保存异常信息
            enumDataAnomalyMap.put(iotDataItem.getFactorCode(), enumDataAnomaly);
            // 计算因子最高的异常级别
            exceptionLevel = NumberUtil.max(exceptionLevel, enumDataAnomaly.getExceptionLevel());
            // 保存计算后结果
            fmDataRecordItemBos.add(fmDataRecordItemBo);
        }
        // 如果是2061则执行数据同步 - 补充如果有异常也进行数据同步
        if (CollUtil.contains(ListUtil.of(Constant212.CN_2061, Constant212.CN_2051, Constant212.CN_2031), iotData.getCn())
                || isException) {
            // 初始化数据记录 - 开放平台
            FmDataRecordBo fmDataRecordBo = initDataRecord(map.getOrDefault(iotData.getMn(), iotData.getMn()), iotData.getCn(),
                    ruleId.get(), DateUtil.formatLocalDateTime(iotData.getReportTime()), exceptionLevel);
            // 保存数据记录详情
            for (FmDataRecordItemBo fmDataRecordItemBo : fmDataRecordItemBos) {
                // 数据id赋值
                fmDataRecordItemBo.setDataId(fmDataRecordBo.getId());
                // 初始化并保存因子记录详情
                ToolFmData.initDataItem(fmDataRecordItemBo, iotData.getMn());
                // 执行消息推送
                EnumDataAnomaly enumDataAnomaly = enumDataAnomalyMap.get(fmDataRecordItemBo.getFactorCode());
                // 判断-如果存在异常，则执行推送
                if (enumDataAnomaly.isException()) {
                    msgPush(iotData, fmDataRecordRuleMap, fmDataRecordItemBo, enumDataAnomaly, isException);
                }
            }
        }
        // 雨量天气等计算
        rainSiteHandle(iotData, isException);
        // 智能排污异常触发逻辑 - 污染源地表水
        handle(iotData, isException);
        // 更新设备配置信息
        optFmDevice.updateDeviceConfig(iotData.getMn());
        return true;
    }

    /**
     * 预警消息推送
     * @param iotData
     * @param fmDataRecordRuleMap
     * @param fmDataRecordItemBo
     * @param enumDataAnomaly
     * @param finalIsException
     */
    private static void msgPush(IotData iotData, Map<String, FmDataRecordRule> fmDataRecordRuleMap, FmDataRecordItemBo fmDataRecordItemBo, EnumDataAnomaly enumDataAnomaly, boolean finalIsException) {
        UtilRun.jitterRun(StrUtil.format("fm-data-push-event-{}-{}", iotData.getMn(), fmDataRecordItemBo.getFactorCode()), () -> {
            // 生成并保存消息
            if (OPT_FM_DATA_PUSH.genAndSaveMsg(iotData.getMn(), fmDataRecordItemBo.getId(),
                    ObjectUtil.defaultIfBlank(fmDataRecordItemBo.getFactorName(), fmDataRecordItemBo.getFactorCode()) + enumDataAnomaly.getMemo())) {
                Entity siteInfo = ToolFmData.findSiteInfo(iotData.getMn());

                Entity omUser = ToolFmData.findOmUser(siteInfo.getStr("om_user_id"));

                // 推送给对应人员
                if (ObjectUtil.isNotNull(omUser)) {
                    String siteName = siteInfo.getStr("site_name");
                    AtomicReference<String> factorName = new AtomicReference<>(fmDataRecordItemBo.getFactorCode());
                    Opt.ofNullable(fmDataRecordRuleMap.get(fmDataRecordItemBo.getFactorCode())).ifPresent(fmDataRecordRule -> factorName.set(fmDataRecordRule.getFactorName()));
                    String phone = omUser.getStr("phone");
                    // APP推送
                    UtilFmMsg.msgPushApp(siteName, enumDataAnomaly.getMemo(), factorName + enumDataAnomaly.getMemo(), phone);
                    // 短信推送
                    if (finalIsException) {
//                        UtilFmMsg.msgPushSms(siteName, enumDataAnomaly.getMemo(), factorName + enumDataAnomaly.getMemo(), phone);
                    }
                }
            }
        }, 1000 * 60 * 60);
    }

    private static void rainSiteHandle(IotData iotData, boolean isException) {
        // 液位
        IotDataItem f10011 = CollUtil.findOne(iotData.getIotDataItems(), iotDataItem -> iotDataItem.getFactorCode().equals("f10011"));
        // 下雨级别
        IotDataItem f11002 = CollUtil.findOne(iotData.getIotDataItems(), iotDataItem -> iotDataItem.getFactorCode().equals("f11002"));
        // 流量
        IotDataItem f10001 = CollUtil.findOne(iotData.getIotDataItems(), iotDataItem -> iotDataItem.getFactorCode().equals("f10001"));
        if (ObjectUtil.isNotNull(f10011) && ObjectUtil.isNotNull(f11002) && ObjectUtil.isNotNull(f10001)) {
            boolean isFlowingWater = NumberUtil.parseDouble(f10001.getFactorValRtd()) > 0.1d
                    || NumberUtil.parseDouble(f10011.getFactorValRtd()) > 0.1d;
            // 数据异常计算 - 雨污站
            // 计算去重前缀
            String eventKey = StrUtil.format("com-ywz-data-event-{}-", iotData.getMn());
            if (f11002.getFactorValRtd().equals("1")) {
                if (isFlowingWater) {
                    if (isException) {
                        UtilRun.jitterRun(eventKey + "3", () -> {
                            // 企业偷排 - 晴天排水并超标
                            ToolFmData.OPT_FM_DATA_PUSH.genData(iotData.getMn(), "-1", "疑似企业偷排漏排", 3);
                        }, 1000 * 60 * 30);
                    } else {
                        UtilRun.jitterRun(eventKey + "2", () -> {
                            // 管网错接 - 晴天排水
                            ToolFmData.OPT_FM_DATA_PUSH.genData(iotData.getMn(), "-1", "疑似管网错接或偷排", 2);
                        }, 1000 * 60 * 30);
                    }
                }
            } else {
                if(!isFlowingWater) {
                    UtilRun.jitterRun(eventKey + "4", () -> {
                        // 管网堵塞或破损
                        ToolFmData.OPT_FM_DATA_PUSH.genData(iotData.getMn(), "-1", "疑似管网堵塞或破损", 4);
                    }, 1000 * 60 * 30);
                }
                if (isFlowingWater && isException) {
                    UtilRun.jitterRun(eventKey + "5", () -> {
                        // 污水混入 - 雨天排水并超标
                        ToolFmData.OPT_FM_DATA_PUSH.genData(iotData.getMn(), "-1", "疑似污水混入", 5);
                    }, 1000 * 60 * 30);
                }
            }
        }
    }

    /**
     * 特殊逻辑执行，实时数据不进行推送 - 执行特殊逻辑
     * @param iotData
     * @param isException
     */
    private static void handle(IotData iotData, boolean isException) {
        // 查询产品信息
        ThingsProductDo byDeviceCode = ToolOpt.OPT_T_PRODUCT.getByDeviceCode(iotData.getMn());
        // 智能排污 - 并且数据超标异常执行，并且产品是智能排污产品执行
        if (isException && "9c65b17bcd6a4824a8b91dbcb5f13c69".equals(byDeviceCode.getId())) {
            // 补充时间逻辑 - 超过三小时的数据不触发执行
            DateTime date = DateUtil.date(iotData.getReportTime());
            // 判断上报时间增加3小时 > 当前时间，则执行应急触发逻辑
            if (DateUtil.compare(DateUtil.offsetHour(date, 3), DateUtil.date()) > 0) {
                Tool212.pushSt32Emergency(iotData.getMn(), StrUtil.format("数据[{}][{}]超标", iotData.getMn(), iotData.getReportTime()));
            }
        }
    }

    /**
     * 异常计算，对象赋值
     * @param recordRule
     * @param dataRecordItem
     * @return
     */
    private static EnumDataAnomaly handleDataStand(FmDataRecordRule recordRule, FmDataRecordItemBo dataRecordItem) {
        if (ObjectUtil.isNull(recordRule) || StrUtil.isBlank(dataRecordItem.getFactorValue())) {
            return EnumDataAnomaly.NONE;
        }
        if (!NumberUtil.isNumber(dataRecordItem.getFactorValue())) {
            return EnumDataAnomaly.NONE;
        }
        double valDouble = NumberUtil.parseDouble(dataRecordItem.getFactorValue());
        // 判断异常
        int isE = recordRule.isE(valDouble);
        int isO = recordRule.isO(valDouble);
        int isA = recordRule.isA(valDouble);

        if (StrUtil.isBlank(dataRecordItem.getFactorName())) {
            dataRecordItem.setFactorName(recordRule.getFactorName());
        }

        if (isE != 0) {
            dataRecordItem.setIsE(1);
            dataRecordItem.setIsO(1);
            dataRecordItem.setIsA(1);
            dataRecordItem.setEType(0);
            if (isE == -1) {
                dataRecordItem.setEType(1);
                return EnumDataAnomaly.EXCEPTION_DOWN;
            }
            return EnumDataAnomaly.EXCEPTION_TOP;
        }
        // 判断超标
        if (isO != 0) {
            dataRecordItem.setIsO(1);
            dataRecordItem.setIsA(1);
            dataRecordItem.setOType(0);
            if (isO == -1) {
                dataRecordItem.setOType(1);
                return EnumDataAnomaly.OVER_DOWN;
            }
            return EnumDataAnomaly.OVER_TOP;
        }
        // 判断告警
        if (isA != 0) {
            dataRecordItem.setIsA(1);
            return isA == 1 ? EnumDataAnomaly.ALARM_TOP : EnumDataAnomaly.ALARM_DOWN;
        }
        return EnumDataAnomaly.NONE;
    }

    public static void main(String[] args) {
        StaticLog.info(JSONUtil.toJsonStr(new OptFmData().newData("41010501G00001")));
    }
}
